package com.ruoyi.modules.service.impl;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.modules.domain.dto.FansSourceDTO;
import com.ruoyi.modules.domain.dto.VideoDataDTO;
import com.ruoyi.modules.domain.vo.DyAppUserDTO;
import com.ruoyi.modules.service.IDyWorkWordService;
import com.ruoyi.modules.util.DouyinRequestUtil;
import org.redisson.api.RedissonClient;
import org.slf4j.helpers.MessageFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import com.ruoyi.modules.mapper.DyAppUserMapper;
import com.ruoyi.modules.domain.DyAppUser;
import com.ruoyi.modules.service.IDyAppUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 抖音app用户Service业务层处理
 *
 * @author ruoyi
 * @date 2022-01-22
 */
@Service
public class DyAppUserServiceImpl extends ServiceImpl<DyAppUserMapper, DyAppUser> implements IDyAppUserService {

    @Autowired
    RedisCache redisCache;
    @Autowired
    RedissonClient redissonClient;

    @Autowired
    IDyWorkWordService dyWorkWordService;

    private static final String  dyAppUserDTo_key = "dyApp:";

    private static final String  VIDEO_LIST_CACHE_KEY = "videoListData:";
    private static final String  VIDEO_LIST_LOCK_KEY = "videoListLock:";

    private static String natureFlow = "feed视频(非推人)";
    private static Map<String, String> fansSourceMap = new HashMap<>();

    static {
        fansSourceMap.put("搜索", "搜索流量");
        fansSourceMap.put(natureFlow, "自然流量推送");
        fansSourceMap.put("视频详情页", "视频详情页");
        fansSourceMap.put("他人页", "他人主页");
        fansSourceMap.put("其它", "西G头T");
        fansSourceMap.put("他人关注列表", "他人关注页");
    }

    private static ThreadPoolTaskExecutor activateExecutor = null;

    static {
        activateExecutor = new ThreadPoolTaskExecutor();
        activateExecutor.initialize();
        activateExecutor.setCorePoolSize(20);
        activateExecutor.setMaxPoolSize(100);
        activateExecutor.setQueueCapacity(1000);
        activateExecutor.setKeepAliveSeconds(300);
        // 线程池对拒绝任务(无线程可用)的处理策略
        activateExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    }

    @Override
    public List<DyAppUser> listDyAppUser(Long agentUserId, String appUserNickname, String appUserCode) {

        return baseMapper.appUserNickname(agentUserId, appUserNickname, appUserCode);

    }

    @Override
    public void setDyAppUserDTo(String voucher, DyAppUserDTO dyAppUserDTO) {
        redisCache.setCacheObject(dyAppUserDTo_key + voucher, dyAppUserDTO, 10 * 60 * 60, TimeUnit.SECONDS);
    }

    @Override
    public DyAppUserDTO getDyAppUserDTo(String voucher) {
        return redisCache.getCacheObject(dyAppUserDTo_key + voucher);
    }



    @Override
    public Object generalizeData(String voucher) throws ExecutionException, InterruptedException {
        System.out.println("************************generalizeData");
        DyAppUserDTO dyAppUserDTO = this.getDyAppUserDTo(voucher);
        Map<String, Object> map = new ConcurrentHashMap<>();

        Future<?> fansSourceResult = activateExecutor.submit(() -> this.generalizeFansSource(dyAppUserDTO, map));
        Future<?> videoResult = activateExecutor.submit(() -> this.generalizeVideo(voucher, dyAppUserDTO, map));



        fansSourceResult.get();
        videoResult.get();

        return map;
    }



    /**
     * 粉丝来源
     * @param dyAppUserDTO
     * @param map
     */
    private void generalizeFansSource(DyAppUserDTO dyAppUserDTO, Map<String, Object> map) {
        JSONObject jsonObject = DouyinRequestUtil.fansSource(dyAppUserDTO.getOpenId(), dyAppUserDTO.getAccessToken());
        map.put("fansSource", jsonObject);

        String listJson = jsonObject.getString("list");
        List<FansSourceDTO> fansSourceDTOList = JSON.parseArray(listJson, FansSourceDTO.class);
        if (null != fansSourceDTOList && 0 != fansSourceDTOList.size()){

            FansSourceDTO max = fansSourceDTOList.stream()
                    .filter(e-> !natureFlow.equals(e.getSource()))
                    .max(Comparator.comparing(e -> new BigDecimal(e.getPercent().replace("%", ""))))
                    .get();
            if (null != max) {
                map.put("adjustFlow", max.getSource() + max.getPercent() + "(建议减低)" );
            }

            fansSourceDTOList.forEach(item->{
                if (natureFlow.equals(item.getSource())){
                    map.put("natureFlow", item.getPercent() + "不及格");
                }
                item.setSource(fansSourceMap.get(item.getSource()));
            });
        }

    }


    /**
     * 视频相关
     * @param voucher
     * @param map
     */
    private void generalizeVideo(String voucher, DyAppUserDTO dyAppUserDTO, Map<String, Object> map){
        VideoDataDTO videoDataDTO = this.videoList(voucher, dyAppUserDTO, null);
        map.put("videoDataDTO", videoDataDTO);

        List<VideoDataDTO.VideoItem> videoList = videoDataDTO.getList();
        if (null != videoList && 0 != videoList.size()) {

            VideoDataDTO.VideoItem videoItem = videoList.stream().max(Comparator.comparing((a) -> {
                return a.getStatistics().getPlay_count();
            })).get();
            if (null != videoItem){
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm");
                map.put("bestTime", simpleDateFormat.format(new Date(videoItem.getCreate_time())));
                map.put("flowName", getFlowName(videoItem.getStatistics().getPlay_count()));
            }

            //视频发布状态
            try {
                handleTime(videoList, map);
            } catch (ParseException e) {
                e.printStackTrace();
            }


            List<String> wordList = dyWorkWordService.listWord();
            List<String> videoLabelList = new ArrayList<>();
            videoList.forEach(video->{
                int i = video.getTitle().indexOf("#");
                if (i != -1){
                    String labelWork = video.getTitle().substring(i, video.getTitle().length() - 1);
                    wordList.forEach(work->{
                        if (labelWork.indexOf(work) != -1) {
                            videoLabelList.add(work);
                        }
                    });
                }
            });
            List<String> new_videoLabelList = videoLabelList.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
                    .entrySet().stream().sorted(Map.Entry.comparingByValue()).map(Map.Entry::getKey).collect(Collectors.toList());

            map.put("videoLabels", StringUtils.join(new_videoLabelList, ", "));

        }
    }



    private String getFlowName(Long playNum){
        if (null == playNum) return null;
        if (playNum >= 10000000) return "千万人流量池";
        if (playNum >= 1000000) return "百万人流量池";
        if (playNum >= 100000) return "十万人流量池";
        if (playNum >= 10000) return "万人流量池";
        if (playNum >= 1000) return "千人流量池";
        if (playNum >= 100) return "百人流量池";
        if (playNum >= 10) return "十人流量池";
        return "" + playNum;
    }

    @Override
    public VideoDataDTO videoList(String voucher, DyAppUserDTO dyAppUserDTO, Long cursor) {

        cursor = Optional.ofNullable(cursor).orElse(0L);

        VideoDataDTO data = DouyinRequestUtil.videoList(dyAppUserDTO.getOpenId(), dyAppUserDTO.getAccessToken(), cursor);
        List<VideoDataDTO.VideoItem> list = Optional.ofNullable(data.getList()).orElse(Collections.emptyList());
        list = list.stream().filter(item -> item.getCreate_time() != 0).collect(Collectors.toList());
        data.setList(list);
        return data;

//        VideoDataDTO data = null;
//        String key = VIDEO_LIST_CACHE_KEY + voucher + ":" + cursor;
//        data = redisCache.getCacheObject(key);
//        if (data == null){
//
//        }
//        return data;
    }







    private void handleTime(List<VideoDataDTO.VideoItem> videoList, Map<String, Object> map) throws ParseException {
        //日期格式化
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        List<String> timeList = videoList.stream().sorted(Comparator.comparing(VideoDataDTO.VideoItem::getCreate_time))
                .map(e -> df.format(new Date(e.getCreate_time() * 1000))).distinct().collect(Collectors.toList());

//        List<Calendar> lackList = getTimeListByDay(df.parse(timeList.get(0)), df.parse(timeList.get(timeList.size() - 1)), timeList);
        List<Calendar> lackList = getTimeListByDay(df.parse(timeList.get(0)), new Date(), timeList);



        System.out.println(lackList);
        Map<Integer, Long> weekMap = lackList.stream().collect(Collectors.groupingBy(e -> e.get(Calendar.WEEK_OF_YEAR), Collectors.counting()));
        Map<Integer, Long> monthMap = lackList.stream().collect(Collectors.groupingBy(e -> e.get(Calendar.MONTH), Collectors.counting()));


        Calendar currentCalendar = Calendar.getInstance();
        currentCalendar.setTime(new Date());
        List<String> lackMsgList = new ArrayList<>();

        Long week_count_current = weekMap.get(currentCalendar.get(Calendar.WEEK_OF_YEAR));
        Long week_count_pre = weekMap.get(currentCalendar.get(Calendar.WEEK_OF_YEAR) - 1);
        Long week_count = Math.max(Optional.ofNullable(week_count_current).orElse(0L), Optional.ofNullable(week_count_pre).orElse(0L));
        if (week_count != 0){
            lackMsgList.add(MessageFormatter.format("周断更（{}回）", week_count).getMessage());
        }


        Long month_count_current = monthMap.get(currentCalendar.get(Calendar.MONTH));
        Long month_count_pre = monthMap.get(currentCalendar.get(Calendar.MONTH) - 1);
        Long month_count = Math.max(Optional.ofNullable(month_count_current).orElse(0L), Optional.ofNullable(month_count_pre).orElse(0L));
        if (month_count != 0){
            lackMsgList.add(MessageFormatter.format("月断更（{}回）", month_count).getMessage());
        }


        lackMsgList = lackMsgList.stream().distinct().collect(Collectors.toList());
        map.put("updateLack", StringUtils.join(lackMsgList, ", "));
    }



    private static List<Calendar> getTimeListByDay(Date startDate, Date endDate, List<String> timeList) {
        Calendar start = Calendar.getInstance();
        start.setTime(startDate);
        Calendar end = Calendar.getInstance();
        end.setTime(endDate);

        start.set(Calendar.HOUR_OF_DAY, 0);
        end.set(Calendar.HOUR_OF_DAY, 23);
        int range = new BigDecimal((double) (end.getTimeInMillis() - start.getTimeInMillis()) / 1000 / 60 /60 /24).setScale(0, BigDecimal.ROUND_HALF_UP).abs().intValue();


        ArrayList<Calendar> list = new ArrayList<>();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        end.set(Calendar.DAY_OF_YEAR, end.get(Calendar.DAY_OF_YEAR));
        for (int i=1;i<range;i++){
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startDate);
            calendar.add(Calendar.DAY_OF_MONTH, i);
            if (!timeList.contains(df.format(calendar.getTime()))) {
                list.add(calendar);

            }
        }
        return list;
    }


}
